From a608bc4566fd9f5fe5cb74e2143e062350cffdfe Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sat, 9 Jul 2005 07:58:56 -0700 Subject: [PATCH] Intel's pre-bk->hg transition patches Signed-off-by Eddie Dong Signed-off-by Anthony Xu Signed-off-by Kevin Tian --- xen/arch/ia64/Makefile | 2 +- xen/arch/ia64/asm-offsets.c | 1 + xen/arch/ia64/domain.c | 125 ++++++++- xen/arch/ia64/mm.c | 17 +- xen/arch/ia64/mmio.c | 386 +++++++++++++++++++--------- xen/arch/ia64/pal_emul.c | 283 ++++++++++++++++++++ xen/arch/ia64/vlsapic.c | 217 +++++++++++----- xen/arch/ia64/vmx_entry.S | 2 +- xen/arch/ia64/vmx_hypercall.c | 24 +- xen/arch/ia64/vmx_init.c | 23 +- xen/arch/ia64/vmx_ivt.S | 54 ++-- xen/arch/ia64/vmx_minstate.h | 6 +- xen/arch/ia64/vmx_phy_mode.c | 95 +++++-- xen/arch/ia64/vmx_process.c | 57 +++- xen/arch/ia64/vmx_support.c | 159 ++++++++++++ xen/arch/ia64/vmx_vcpu.c | 39 +-- xen/arch/ia64/vmx_virt.c | 15 +- xen/arch/ia64/vtlb.c | 9 +- xen/arch/ia64/xensetup.c | 1 - xen/include/asm-ia64/config.h | 1 + xen/include/asm-ia64/domain.h | 4 +- xen/include/asm-ia64/privop.h | 18 ++ xen/include/asm-ia64/vmx.h | 2 + xen/include/asm-ia64/vmx_phy_mode.h | 1 + xen/include/asm-ia64/vmx_vcpu.h | 22 +- xen/include/asm-ia64/vmx_vpd.h | 8 +- xen/include/asm-ia64/xenprocessor.h | 10 + xen/include/asm-ia64/xensystem.h | 2 + xen/include/public/arch-ia64.h | 10 + 29 files changed, 1285 insertions(+), 308 deletions(-) create mode 100644 xen/arch/ia64/pal_emul.c create mode 100644 xen/arch/ia64/vmx_support.c diff --git a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile index d2be0994ab..5e497818cc 100644 --- a/xen/arch/ia64/Makefile +++ b/xen/arch/ia64/Makefile @@ -15,7 +15,7 @@ OBJS = xensetup.o setup.o time.o irq.o ia64_ksyms.o process.o smp.o \ ifeq ($(CONFIG_VTI),y) OBJS += vmx_init.o vmx_virt.o vmx_vcpu.o vmx_process.o vmx_vsa.o vmx_ivt.o \ vmx_phy_mode.o vmx_utility.o vmx_interrupt.o vmx_entry.o vmmu.o \ - vtlb.o mmio.o vlsapic.o vmx_hypercall.o mm.o + vtlb.o mmio.o vlsapic.o vmx_hypercall.o mm.o vmx_support.o pal_emul.o endif # perfmon.o # unwind.o needed for kernel unwinding (rare) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 9c2326a6a0..43589b6586 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -224,6 +224,7 @@ void foo(void) #ifdef CONFIG_VTI DEFINE(IA64_VPD_BASE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.vpd)); + DEFINE(IA64_VLSAPIC_INSVC_BASE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.in_service[0])); DEFINE(IA64_VPD_CR_VPTA_OFFSET, offsetof (cr_t, pta)); DEFINE(XXX_THASH_SIZE, sizeof (thash_data_t)); diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c index c6ead10510..5929f17d11 100644 --- a/xen/arch/ia64/domain.c +++ b/xen/arch/ia64/domain.c @@ -37,10 +37,13 @@ #include /* for IA64_THREAD_INFO_SIZE */ #include /* for function declarations */ +#include #ifdef CONFIG_VTI #include #include +#include #include +#include #endif // CONFIG_VTI #define CONFIG_DOMAIN0_CONTIGUOUS @@ -203,18 +206,20 @@ void arch_do_createdomain(struct vcpu *v) * after up. */ d->shared_info = (void *)alloc_xenheap_page(); + /* Now assume all vcpu info and event indicators can be + * held in one shared page. Definitely later we need to + * consider more about it + */ - /* FIXME: Because full virtual cpu info is placed in this area, - * it's unlikely to put it into one shareinfo page. Later - * need split vcpu context from vcpu_info and conforms to - * normal xen convention. + memset(d->shared_info, 0, PAGE_SIZE); + v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; + /* Mask all events, and specific port will be unmasked + * when customer subscribes to it. */ - v->vcpu_info = (void *)alloc_xenheap_page(); - if (!v->vcpu_info) { - printk("ERROR/HALTING: CAN'T ALLOC PAGE\n"); - while (1); + if(v == d->vcpu[0]) { + memset(&d->shared_info->evtchn_mask[0], 0xff, + sizeof(d->shared_info->evtchn_mask)); } - memset(v->vcpu_info, 0, PAGE_SIZE); /* Allocate per-domain vTLB and vhpt */ v->arch.vtlb = init_domain_tlb(v); @@ -291,6 +296,7 @@ void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) c->shared = v->domain->shared_info->arch; } +#ifndef CONFIG_VTI int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) { struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; @@ -312,6 +318,79 @@ int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) v->domain->shared_info->arch = c->shared; return 0; } +#else // CONFIG_VTI +int arch_set_info_guest( + struct vcpu *v, struct vcpu_guest_context *c) +{ + struct domain *d = v->domain; + int i, rc, ret; + unsigned long progress = 0; + + if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) + return 0; + + /* Lazy FP not implemented yet */ + clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); + if ( c->flags & VGCF_FPU_VALID ) + set_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); + + /* Sync d/i cache conservatively, after domain N is loaded */ + ret = ia64_pal_cache_flush(3, 0, &progress, NULL); + if (ret != PAL_STATUS_SUCCESS) + panic("PAL CACHE FLUSH failed for dom[%d].\n", + v->domain->domain_id); + DPRINTK("Sync i/d cache for dom%d image SUCC\n", + v->domain->domain_id); + + /* Physical mode emulation initialization, including + * emulation ID allcation and related memory request + */ + physical_mode_init(v); + + /* FIXME: only support PMT table continuously by far */ + d->arch.pmt = __va(c->pt_base); + d->arch.max_pfn = c->pt_max_pfn; + v->arch.arch_vmx.vmx_platform.shared_page_va = __va(c->share_io_pg); + memset((char *)__va(c->share_io_pg),0,PAGE_SIZE); + + if (c->flags & VGCF_VMX_GUEST) { + if (!vmx_enabled) + panic("No VMX hardware feature for vmx domain.\n"); + + vmx_final_setup_domain(d); + + /* One more step to enable interrupt assist */ + set_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags); + } + + vlsapic_reset(v); + vtm_init(v); + + /* Only open one port for I/O and interrupt emulation */ + if (v == d->vcpu[0]) { + memset(&d->shared_info->evtchn_mask[0], 0xff, + sizeof(d->shared_info->evtchn_mask)); + clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_mask[0]); + } + /* Setup domain context. Actually IA-64 is a bit different with + * x86, with almost all system resources better managed by HV + * directly. CP only needs to provide start IP of guest, which + * ideally is the load address of guest Firmware. + */ + new_thread(v, c->guest_iip, 0, 0); + + + d->xen_vastart = 0xf000000000000000; + d->xen_vaend = 0xf300000000000000; + d->arch.breakimm = 0x1000 + d->domain_id; + v->arch._thread.on_ustack = 0; + + /* Don't redo final setup */ + set_bit(_VCPUF_initialised, &v->vcpu_flags); + + return 0; +} +#endif // CONFIG_VTI void arch_do_boot_vcpu(struct vcpu *v) { @@ -361,7 +440,10 @@ void new_thread(struct vcpu *v, init_all_rr(v); if (VMX_DOMAIN(v)) { - VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); + if (d == dom0) { + VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); + printk("new_thread, done with dom_fw_setup\n"); + } /* Virtual processor context setup */ VMX_VPD(v, vpsr) = IA64_PSR_BN; VPD_CR(v, dcr) = 0; @@ -556,6 +638,7 @@ tryagain: } // FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE +#ifndef CONFIG_VTI unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) { unsigned long pte = lookup_domain_mpa(d,mpaddr); @@ -566,6 +649,14 @@ unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) imva |= mpaddr & ~PAGE_MASK; return(imva); } +#else // CONFIG_VTI +unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) +{ + unsigned long imva = __gpa_to_mpa(d, mpaddr); + + return __va(imva); +} +#endif // CONFIG_VTI // remove following line if not privifying in memory //#define HAVE_PRIVIFY_MEMORY @@ -812,6 +903,17 @@ void build_shared_info(struct domain *d) /* ... */ } +/* + * Domain 0 has direct access to all devices absolutely. However + * the major point of this stub here, is to allow alloc_dom_mem + * handled with order > 0 request. Dom0 requires that bit set to + * allocate memory for other domains. + */ +void physdev_init_dom0(struct domain *d) +{ + set_bit(_DOMF_physdev_access, &d->domain_flags); +} + extern unsigned long running_on_sim; unsigned int vmx_dom0 = 0; int construct_dom0(struct domain *d, @@ -963,6 +1065,7 @@ int construct_dom0(struct domain *d, set_bit(_DOMF_constructed, &d->domain_flags); new_thread(v, pkern_entry, 0, 0); + physdev_init_dom0(d); // FIXME: Hack for keyboard input #ifdef CLONE_DOMAIN0 if (d == dom0) @@ -978,6 +1081,8 @@ if (d == dom0) return 0; } + + #else //CONFIG_VTI int construct_dom0(struct domain *d, diff --git a/xen/arch/ia64/mm.c b/xen/arch/ia64/mm.c index 755596f89e..deeccbbe67 100644 --- a/xen/arch/ia64/mm.c +++ b/xen/arch/ia64/mm.c @@ -95,7 +95,7 @@ #include #include #include - +#include /* uregs->ptr is virtual address uregs->val is pte value @@ -109,8 +109,9 @@ int do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom) mmu_update_t req; ia64_rr rr; thash_cb_t *hcb; - thash_data_t entry={0}; + thash_data_t entry={0},*ovl; vcpu = current; + search_section_t sections; hcb = vmx_vcpu_get_vtlb(vcpu); for ( i = 0; i < count; i++ ) { @@ -124,8 +125,18 @@ int do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom) entry.cl = DSIDE_TLB; rr = vmx_vcpu_rr(vcpu, req.ptr); entry.ps = rr.ps; + entry.key = redistribute_rid(rr.rid); entry.rid = rr.rid; - vtlb_insert(hcb, &entry, req.ptr); + entry.vadr = PAGEALIGN(req.ptr,entry.ps); + sections.tr = 1; + sections.tc = 0; + ovl = thash_find_overlap(hcb, &entry, sections); + if (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + thash_purge_and_insert(hcb, &entry); }else if(cmd == MMU_MACHPHYS_UPDATE){ mfn = req.ptr >>PAGE_SHIFT; gpfn = req.val; diff --git a/xen/arch/ia64/mmio.c b/xen/arch/ia64/mmio.c index 2fb5c34251..6a3f4873c6 100644 --- a/xen/arch/ia64/mmio.c +++ b/xen/arch/ia64/mmio.c @@ -27,7 +27,13 @@ #include #include #include +#include +#include +#include +#include +#include +/* struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) { int i; @@ -37,54 +43,183 @@ struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) } return NULL; } +*/ +#define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) +#define PIB_OFST_INTA 0x1E0000 +#define PIB_OFST_XTP 0x1E0008 -extern void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma); -static inline void mmio_write(VCPU *vcpu, void *src, u64 dest_pa, size_t s, int ma) +static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) { - struct virutal_platform_def *v_plat; - struct mmio_list *mio; - - v_plat = vmx_vcpu_get_plat(vcpu); - mio = lookup_mmio(dest_pa, v_plat->mmio); - if ( mio == NULL ) - panic ("Wrong address for MMIO\n"); - - switch (mio->iot) { - case PIB_MMIO: - pib_write(vcpu, src, dest_pa - v_plat->pib_base, s, ma); + switch (pib_off) { + case PIB_OFST_INTA: + panic("Undefined write on PIB INTA\n"); + break; + case PIB_OFST_XTP: + if ( s == 1 && ma == 4 /* UC */) { + vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src; + } + else { + panic("Undefined write on PIB XTP\n"); + } + break; + default: + if ( PIB_LOW_HALF(pib_off) ) { // lower half + if ( s != 8 || ma != 0x4 /* UC */ ) { + panic("Undefined IPI-LHF write!\n"); + } + else { + write_ipi(vcpu, pib_off, *(uint64_t *)src); + // TODO for SM-VP + } + } + else { // upper half + printf("IPI-UHF write %lx\n",pib_off); + panic("Not support yet for SM-VP\n"); + } + break; + } +} + +static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) +{ + switch (pib_off) { + case PIB_OFST_INTA: + // todo --- emit on processor system bus. + if ( s == 1 && ma == 4) { // 1 byte load + // TODO: INTA read from IOSAPIC + } + else { + panic("Undefined read on PIB INTA\n"); + } + break; + case PIB_OFST_XTP: + if ( s == 1 && ma == 4) { + *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp; + } + else { + panic("Undefined read on PIB XTP\n"); + } break; - case VGA_BUFF: - case CHIPSET_IO: - case LOW_MMIO: - case LEGACY_IO: - case IO_SAPIC: default: + if ( PIB_LOW_HALF(pib_off) ) { // lower half + if ( s != 8 || ma != 4 ) { + panic("Undefined IPI-LHF read!\n"); + } + else { +#ifdef IPI_DEBUG + printf("IPI-LHF read %lx\n",pib_off); +#endif + *(uint64_t *)dest = 0; // TODO for SM-VP + } + } + else { // upper half + if ( s != 1 || ma != 4 ) { + panic("Undefined PIB-UHF read!\n"); + } + else { +#ifdef IPI_DEBUG + printf("IPI-UHF read %lx\n",pib_off); +#endif + *(uint8_t *)dest = 0; // TODO for SM-VP + } + } break; } +} + +static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = (vcpu_iodata_t *) v->arch.arch_vmx.vmx_platform.shared_page_va; + if (vio == 0) { + panic("bad shared page: %lx", (unsigned long)vio); + } + p = &vio->vp_ioreq; + p->addr = pa; + p->size = 1<count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 1; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(IOPACKET_PORT); + vmx_wait_io(); + if(dir){ //read + *val=p->u.data; + } return; } +#define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3)) -static inline void mmio_read(VCPU *vcpu, u64 src_pa, void *dest, size_t s, int ma) +static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = (vcpu_iodata_t *) v->arch.arch_vmx.vmx_platform.shared_page_va; + if (vio == 0) { + panic("bad shared page: %lx"); + } + p = &vio->vp_ioreq; + p->addr = TO_LEGACY_IO(pa&0x3ffffffUL); + p->size = 1<count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 0; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(IOPACKET_PORT); + vmx_wait_io(); + if(dir){ //read + *val=p->u.data; + } + return; +} + +static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir) { struct virutal_platform_def *v_plat; - struct mmio_list *mio; - + //mmio_type_t iot; + unsigned long iot; + iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT); v_plat = vmx_vcpu_get_plat(vcpu); - mio = lookup_mmio(src_pa, v_plat->mmio); - if ( mio == NULL ) - panic ("Wrong address for MMIO\n"); - - switch (mio->iot) { - case PIB_MMIO: - pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + + switch (iot) { + case GPFN_PIB: + if(!dir) + pib_write(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + else + pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); break; - case VGA_BUFF: - case CHIPSET_IO: - case LOW_MMIO: - case LEGACY_IO: - case IO_SAPIC: + case GPFN_GFW: + break; + case GPFN_FRAME_BUFFER: + case GPFN_LOW_MMIO: + low_mmio_access(vcpu, src_pa, dest, s, dir); + break; + case GPFN_LEGACY_IO: + legacy_io_access(vcpu, src_pa, dest, s, dir); + break; + case GPFN_IOSAPIC: default: + panic("Bad I/O access\n"); break; } return; @@ -93,9 +228,9 @@ static inline void mmio_read(VCPU *vcpu, u64 src_pa, void *dest, size_t s, int m /* * Read or write data in guest virtual address mode. */ - +/* void -memwrite_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) +memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) { uint64_t pa; @@ -108,7 +243,7 @@ memwrite_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) void -memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s) +memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) { uint64_t pa = (uint64_t)dest; int ma; @@ -116,9 +251,9 @@ memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s) if ( pa & (1UL <<63) ) { // UC ma = 4; - pa <<=1; + pa <<=1; pa >>=1; - } + } else { // WBL ma = 0; // using WB for WBL @@ -127,7 +262,7 @@ memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s) } void -memread_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) +memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) { uint64_t pa; @@ -135,12 +270,12 @@ memread_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) panic("Normal memory write shouldn't go to this point!"); pa = PPN_2_PA(vtlb->ppn); pa += POFFSET((u64)src, vtlb->ps); - + mmio_read(vcpu, pa, dest, s, vtlb->ma); } void -memread_p(VCPU *vcpu, void *src, void *dest, size_t s) +memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) { uint64_t pa = (uint64_t)src; int ma; @@ -148,19 +283,16 @@ memread_p(VCPU *vcpu, void *src, void *dest, size_t s) if ( pa & (1UL <<63) ) { // UC ma = 4; - pa <<=1; + pa <<=1; pa >>=1; - } + } else { // WBL ma = 0; // using WB for WBL } mmio_read(vcpu, pa, dest, s, ma); } - -#define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) -#define PIB_OFST_INTA 0x1E0000 -#define PIB_OFST_XTP 0x1E0008 +*/ /* @@ -182,23 +314,22 @@ static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) panic ("Inject guest PMI!\n"); break; case 4: // NMI - vmx_vcpu_pend_interrupt (vcpu, 2); + vmx_vcpu_pend_interrupt (vcpu, 2); break; case 5: // INIT // TODO -- inject guest INIT panic ("Inject guest INIT!\n"); break; case 7: // ExtINT - vmx_vcpu_pend_interrupt (vcpu, 0); + vmx_vcpu_pend_interrupt (vcpu, 0); break; - case 1: case 3: case 6: default: panic ("Deliver reserved IPI!\n"); break; - } + } } /* @@ -209,7 +340,6 @@ static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) int i; VCPU *vcpu; LID lid; - for (i=0; ivcpu[i]; lid.val = VPD_CR(vcpu, lid); @@ -226,7 +356,7 @@ static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) { VCPU *target_cpu; - + target_cpu = lid_2_vcpu(vcpu->domain, ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); if ( target_cpu == NULL ) panic("Unknown IPI cpu\n"); @@ -243,83 +373,89 @@ static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) } } -void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) + +/* + dir 1: read 0:write + inst_type 0:integer 1:floating point + */ +extern IA64_BUNDLE __vmx_get_domain_bundle(u64 iip); + + +void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) { - - switch (pib_off) { - case PIB_OFST_INTA: - panic("Undefined write on PIB INTA\n"); - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4 /* UC */) { - vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src; - } - else { - panic("Undefined write on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 0x4 /* UC */ ) { - panic("Undefined IPI-LHF write!\n"); - } - else { - write_ipi(vcpu, pib_off, *(uint64_t *)src); - // TODO for SM-VP - } - } - else { // upper half - printf("IPI-UHF write %lx\n",pib_off); - panic("Not support yet for SM-VP\n"); - } - break; + REGS *regs; + IA64_BUNDLE bundle; + int slot, dir, inst_type=0; + size_t size; + u64 data, value, slot1a, slot1b; + INST64 inst; + regs=vcpu_regs(vcpu); + bundle = __vmx_get_domain_bundle(regs->cr_iip); + slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; + if (!slot) inst.inst = bundle.slot0; + else if (slot == 1){ + slot1a=bundle.slot1a; + slot1b=bundle.slot1b; + inst.inst =slot1a + (slot1b<<18); } -} + else if (slot == 2) inst.inst = bundle.slot2; -void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) -{ - switch (pib_off) { - case PIB_OFST_INTA: - // todo --- emit on processor system bus. - if ( s == 1 && ma == 4) { // 1 byte load - // TODO: INTA read from IOSAPIC - } - else { - panic("Undefined read on PIB INTA\n"); - } - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4) { - *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp; - } - else { - panic("Undefined read on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 4 ) { - panic("Undefined IPI-LHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printf("IPI-LHF read %lx\n",pib_off); -#endif - *(uint64_t *)dest = 0; // TODO for SM-VP - } + if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){ + inst_type=0; //fp + size=(inst.M1.x6&0x3); + if((inst.M1.x6>>2)>0xb){ // write + vmx_vcpu_get_gr(vcpu,inst.M4.r2,&data); + dir=IOREQ_WRITE; //write + }else if((inst.M1.x6>>2)<0xb){ // read + vmx_vcpu_get_gr(vcpu,inst.M1.r1,&value); + dir=IOREQ_READ; + }else{ + printf("This memory access instruction can't be emulated one : %lx\n",inst.inst); + while(1); } - else { // upper half - if ( s != 1 || ma != 4 ) { - panic("Undefined PIB-UHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printf("IPI-UHF read %lx\n",pib_off); -#endif - *(uint8_t *)dest = 0; // TODO for SM-VP + }else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){ + inst_type=1; //fp + dir=IOREQ_READ; + size=3; //ldfd + }else{ + printf("This memory access instruction can't be emulated two: %lx\n ",inst.inst); + while(1); + } + + if(dir==IOREQ_WRITE){ + mmio_access(vcpu, padr, &data, size, ma, dir); + }else{ + mmio_access(vcpu, padr, &data, size, ma, dir); + if(size==0) + data = (value & 0xffffffffffffff00U) | (data & 0xffU); + else if(size==1) + data = (value & 0xffffffffffff0000U) | (data & 0xffffU); + else if(size==2) + data = (value & 0xffffffff00000000U) | (data & 0xffffffffU); + + if(inst_type==0){ //gp + vmx_vcpu_set_gr(vcpu,inst.M1.r1,data,0); + }else{ + panic("Don't support ldfd now !"); +/* switch(inst.M6.f1){ + + case 6: + regs->f6=(struct ia64_fpreg)data; + case 7: + regs->f7=(struct ia64_fpreg)data; + case 8: + regs->f8=(struct ia64_fpreg)data; + case 9: + regs->f9=(struct ia64_fpreg)data; + case 10: + regs->f10=(struct ia64_fpreg)data; + case 11: + regs->f11=(struct ia64_fpreg)data; + default : + ia64_ldfs(inst.M6.f1,&data); } +*/ } - break; } + vmx_vcpu_increment_iip(vcpu); } - diff --git a/xen/arch/ia64/pal_emul.c b/xen/arch/ia64/pal_emul.c new file mode 100644 index 0000000000..f859f17bb0 --- /dev/null +++ b/xen/arch/ia64/pal_emul.c @@ -0,0 +1,283 @@ +/* PAL/SAL call delegation + * + * Copyright (c) 2004 Li Susie + * Copyright (c) 2005 Yu Ke + */ + +#include + +static void +get_pal_parameters (VCPU *vcpu, UINT64 *gr29, + UINT64 *gr30, UINT64 *gr31) { + + vmx_vcpu_get_gr(vcpu,29,gr29); + vmx_vcpu_get_gr(vcpu,30,gr30); + vmx_vcpu_get_gr(vcpu,31,gr31); +} + +static void +set_pal_result (VCPU *vcpu,struct ia64_pal_retval result) { + + vmx_vcpu_set_gr(vcpu,8, result.status,0); + vmx_vcpu_set_gr(vcpu,9, result.v0,0); + vmx_vcpu_set_gr(vcpu,10, result.v1,0); + vmx_vcpu_set_gr(vcpu,11, result.v2,0); +} + + +static struct ia64_pal_retval +pal_cache_flush (VCPU *vcpu) { + UINT64 gr28,gr29, gr30, gr31; + struct ia64_pal_retval result; + + get_pal_parameters (vcpu, &gr29, &gr30, &gr31); + vmx_vcpu_get_gr(vcpu,28,&gr28); + + /* Always call Host Pal in int=1 */ + gr30 = gr30 &(~(0x2UL)); + + /* call Host PAL cache flush */ + result=ia64_pal_call_static(gr28 ,gr29, gr30,gr31,1); // Clear psr.ic when call PAL_CACHE_FLUSH + + /* If host PAL call is interrupted, then loop to complete it */ +// while (result.status == 1) { +// ia64_pal_call_static(gr28 ,gr29, gr30, +// result.v1,1LL); +// } + while (result.status != 0) { + panic("PAL_CACHE_FLUSH ERROR, status %d", result.status); + } + + return result; +} + +static struct ia64_pal_retval +pal_vm_tr_read (VCPU *vcpu ) { +#warning pal_vm_tr_read: to be implemented + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + + +static struct ia64_pal_retval +pal_prefetch_visibility (VCPU *vcpu) { + /* Due to current MM virtualization algorithm, + * We do not allow guest to change mapping attribute. + * Thus we will not support PAL_PREFETCH_VISIBILITY + */ + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_platform_addr(VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= 0; //success + + return result; +} + +static struct ia64_pal_retval +pal_halt (VCPU *vcpu) { +#warning pal_halt: to be implemented + //bugbug: to be implement. + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + + +static struct ia64_pal_retval +pal_halt_light (VCPU *vcpu) { +#if 0 + // GVMM will go back to HVMM and ask HVMM to call yield(). + vmmdata.p_ctlblk->status = VM_OK; + vmmdata.p_ctlblk->ctlcode = ExitVM_YIELD; + + vmm_transition((UINT64)&vmmdata.p_gsa->guest, + (UINT64)&vmmdata.p_gsa->host, + (UINT64) vmmdata.p_tramp,0,0); + + + result.status = 0; + result.pal_result[0]=0; + result.pal_result[1]=0; + result.pal_result[2]=0; + + return result; +#endif + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_read (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_write (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_bus_get_features(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_summary(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_init(VCPU *vcpu){ + struct ia64_pal_retval result; + result.status=0; + return result; +} + +static struct ia64_pal_retval +pal_cache_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_prot_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_shared_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_mem_attrib(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_debug_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_fixed_addr(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_base(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_ratios(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_halt_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_logical_to_physica(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_perf_mon_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_proc_get_features(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_ptce_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_register_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_rse_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_test_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_summary(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_page_size(VCPU *vcpu){ +} + +void +pal_emul( VCPU *vcpu) { + UINT64 gr28; + struct ia64_pal_retval result; + + + vmx_vcpu_get_gr(vcpu,28,&gr28); //bank1 + + switch (gr28) { + case PAL_CACHE_FLUSH: + result = pal_cache_flush (vcpu); + break; + + case PAL_PREFETCH_VISIBILITY: + result = pal_prefetch_visibility (vcpu); + break; + + case PAL_VM_TR_READ: + result = pal_vm_tr_read (vcpu); + break; + + case PAL_HALT: + result = pal_halt (vcpu); + break; + + case PAL_HALT_LIGHT: + result = pal_halt_light (vcpu); + break; + + case PAL_CACHE_READ: + result = pal_cache_read (vcpu); + break; + + case PAL_CACHE_WRITE: + result = pal_cache_write (vcpu); + break; + + case PAL_PLATFORM_ADDR: + result = pal_platform_addr (vcpu); + break; + + default: + panic("pal_emul(): guest call unsupported pal" ); + } + set_pal_result (vcpu, result); +} + + diff --git a/xen/arch/ia64/vlsapic.c b/xen/arch/ia64/vlsapic.c index c25c91d1fa..29a3ef3a93 100644 --- a/xen/arch/ia64/vlsapic.c +++ b/xen/arch/ia64/vlsapic.c @@ -133,7 +133,7 @@ uint64_t vtm_get_itc(VCPU *vcpu) // FIXME: should use local_irq_disable & local_irq_enable ?? local_irq_save(spsr); guest_itc = now_itc(vtm); - update_last_itc(vtm, guest_itc); +// update_last_itc(vtm, guest_itc); local_irq_restore(spsr); return guest_itc; @@ -174,12 +174,12 @@ void vtm_set_itv(VCPU *vcpu) /* Interrupt must be disabled at this point */ extern u64 tick_to_ns(u64 tick); -#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ +#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm) { uint64_t cur_itc,vitm,vitv; uint64_t expires; - long diff_now, diff_last; + long diff_now, diff_last; uint64_t spsr; vitv = VPD_CR(vcpu, itv); @@ -237,21 +237,30 @@ void vtm_domain_in(VCPU *vcpu) #define NMI_VECTOR 2 #define ExtINT_VECTOR 0 - +#define NULL_VECTOR -1 #define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.arch_vmx.in_service[i]) -/* - * LID-CR64: Keep in vpd. - * IVR-CR65: (RO) see guest_read_ivr(). - * TPR-CR66: Keep in vpd, acceleration enabled. - * EOI-CR67: see guest_write_eoi(). - * IRR0-3 - CR68-71: (RO) Keep in vpd irq_pending[] - * can move to vpd for optimization. - * ITV: in time virtualization. - * PMV: Keep in vpd initialized as 0x10000. - * CMCV: Keep in vpd initialized as 0x10000. - * LRR0-1: Keep in vpd, initialized as 0x10000. - * - */ +static void update_vhpi(VCPU *vcpu, int vec) +{ + u64 vhpi; + if ( vec == NULL_VECTOR ) { + vhpi = 0; + } + else if ( vec == NMI_VECTOR ) { // NMI + vhpi = 32; + } else if (vec == ExtINT_VECTOR) { //ExtINT + vhpi = 16; + } + else { + vhpi = vec / 16; + } + + VMX_VPD(vcpu,vhpi) = vhpi; + // TODO: Add support for XENO + if ( VMX_VPD(vcpu,vac).a_int ) { + ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, + (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); + } +} void vlsapic_reset(VCPU *vcpu) { @@ -268,9 +277,11 @@ void vlsapic_reset(VCPU *vcpu) VPD_CR(vcpu, cmcv) = 0x10000; VPD_CR(vcpu, lrr0) = 0x10000; // default reset value? VPD_CR(vcpu, lrr1) = 0x10000; // default reset value? + update_vhpi(vcpu, NULL_VECTOR); for ( i=0; i<4; i++) { VLSAPIC_INSVC(vcpu,i) = 0; } + DPRINTK("VLSAPIC inservice base=%lp\n", &VLSAPIC_INSVC(vcpu,0) ); } /* @@ -281,7 +292,7 @@ void vlsapic_reset(VCPU *vcpu) */ static __inline__ int highest_bits(uint64_t *dat) { - uint64_t bits, bitnum=-1; + uint64_t bits, bitnum; int i; /* loop for all 256 bits */ @@ -292,12 +303,12 @@ static __inline__ int highest_bits(uint64_t *dat) return i*64+bitnum; } } - return -1; + return NULL_VECTOR; } /* * Return 0-255 for pending irq. - * -1 when no pending. + * NULL_VECTOR: when no pending. */ static int highest_pending_irq(VCPU *vcpu) { @@ -320,7 +331,7 @@ static int highest_inservice_irq(VCPU *vcpu) static int is_higher_irq(int pending, int inservice) { return ( (pending >> 4) > (inservice>>4) || - ((pending != -1) && (inservice == -1)) ); + ((pending != NULL_VECTOR) && (inservice == NULL_VECTOR)) ); } static int is_higher_class(int pending, int mic) @@ -333,40 +344,96 @@ static int is_invalid_irq(int vec) return (vec == 1 || ((vec <= 14 && vec >= 3))); } +#define IRQ_NO_MASKED 0 +#define IRQ_MASKED_BY_VTPR 1 +#define IRQ_MASKED_BY_INSVC 2 // masked by inservice IRQ + /* See Table 5-8 in SDM vol2 for the definition */ static int -irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +_xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) { - uint64_t vtpr; + tpr_t vtpr; + uint64_t mmi; - vtpr = VPD_CR(vcpu, tpr); + vtpr.val = VPD_CR(vcpu, tpr); - if ( h_pending == NMI_VECTOR && h_inservice != NMI_VECTOR ) + if ( h_inservice == NMI_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + if ( h_pending == NMI_VECTOR ) { // Non Maskable Interrupt - return 0; - - if ( h_pending == ExtINT_VECTOR && h_inservice >= 16) - return (vtpr>>16)&1; // vtpr.mmi + return IRQ_NO_MASKED; + } + if ( h_inservice == ExtINT_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + mmi = vtpr.mmi; + if ( h_pending == ExtINT_VECTOR ) { + if ( mmi ) { + // mask all external IRQ + return IRQ_MASKED_BY_VTPR; + } + else { + return IRQ_NO_MASKED; + } + } - if ( !(vtpr&(1UL<<16)) && - is_higher_irq(h_pending, h_inservice) && - is_higher_class(h_pending, (vtpr>>4)&0xf) ) - return 0; + if ( is_higher_irq(h_pending, h_inservice) ) { + if ( !mmi && is_higher_class(h_pending, vtpr.mic) ) { + return IRQ_NO_MASKED; + } + else { + return IRQ_MASKED_BY_VTPR; + } + } + else { + return IRQ_MASKED_BY_INSVC; + } +} - return 1; +static int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +{ + int mask; + + mask = _xirq_masked(vcpu, h_pending, h_inservice); + return mask; } + +/* + * May come from virtualization fault or + * nested host interrupt. + */ void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) { uint64_t spsr; if (vector & ~0xff) { - printf("vmx_vcpu_pend_interrupt: bad vector\n"); + DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n"); return; } local_irq_save(spsr); VPD_CR(vcpu,irr[vector>>6]) |= 1UL<<(vector&63); local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; +} + +/* + * Add batch of pending interrupt. + * The interrupt source is contained in pend_irr[0-3] with + * each bits stand for one interrupt. + */ +void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr) +{ + uint64_t spsr; + int i; + + local_irq_save(spsr); + for (i=0 ; i<4; i++ ) { + VPD_CR(vcpu,irr[i]) |= pend_irr[i]; + } + local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; } /* @@ -383,7 +450,7 @@ void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) */ int vmx_check_pending_irq(VCPU *vcpu) { - uint64_t spsr; + uint64_t spsr, mask; int h_pending, h_inservice; int injected=0; uint64_t isr; @@ -391,22 +458,25 @@ int vmx_check_pending_irq(VCPU *vcpu) local_irq_save(spsr); h_pending = highest_pending_irq(vcpu); - if ( h_pending == -1 ) goto chk_irq_exit; + if ( h_pending == NULL_VECTOR ) goto chk_irq_exit; h_inservice = highest_inservice_irq(vcpu); vpsr.val = vmx_vcpu_get_psr(vcpu); - if ( vpsr.i && - !irq_masked(vcpu, h_pending, h_inservice) ) { - //inject_guest_irq(v); + mask = irq_masked(vcpu, h_pending, h_inservice); + if ( vpsr.i && IRQ_NO_MASKED == mask ) { isr = vpsr.val & IA64_PSR_RI; if ( !vpsr.ic ) panic("Interrupt when IC=0\n"); vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ injected = 1; } - else if ( VMX_VPD(vcpu,vac).a_int && - is_higher_irq(h_pending,h_inservice) ) { - vmx_inject_vhpi(vcpu,h_pending); + else if ( mask == IRQ_MASKED_BY_INSVC ) { + // cann't inject VHPI +// DPRINTK("IRQ masked by higher inservice\n"); + } + else { + // masked by vpsr.i or vtpr. + update_vhpi(vcpu,h_pending); } chk_irq_exit: @@ -414,17 +484,21 @@ chk_irq_exit: return injected; } +/* + * Only coming from virtualization fault. + */ void guest_write_eoi(VCPU *vcpu) { int vec; uint64_t spsr; vec = highest_inservice_irq(vcpu); - if ( vec < 0 ) panic("Wrong vector to EOI\n"); + if ( vec == NULL_VECTOR ) panic("Wrong vector to EOI\n"); local_irq_save(spsr); VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); local_irq_restore(spsr); VPD_CR(vcpu, eoi)=0; // overwrite the data + vmx_check_pending_irq(vcpu); } uint64_t guest_read_vivr(VCPU *vcpu) @@ -435,37 +509,54 @@ uint64_t guest_read_vivr(VCPU *vcpu) local_irq_save(spsr); vec = highest_pending_irq(vcpu); h_inservice = highest_inservice_irq(vcpu); - if ( vec < 0 || irq_masked(vcpu, vec, h_inservice) ) { + if ( vec == NULL_VECTOR || + irq_masked(vcpu, vec, h_inservice) != IRQ_NO_MASKED ) { local_irq_restore(spsr); return IA64_SPURIOUS_INT_VECTOR; } VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63)); VPD_CR(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63)); - - h_inservice = highest_inservice_irq(vcpu); - next = highest_pending_irq(vcpu); - if ( VMX_VPD(vcpu,vac).a_int && - (is_higher_irq(next, h_inservice) || (next == -1)) ) - vmx_inject_vhpi(vcpu, next); + update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write local_irq_restore(spsr); return (uint64_t)vec; } -void vmx_inject_vhpi(VCPU *vcpu, u8 vec) +static void generate_exirq(VCPU *vcpu) { - VMX_VPD(vcpu,vhpi) = vec / 16; - + IA64_PSR vpsr; + uint64_t isr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + update_vhpi(vcpu, NULL_VECTOR); + isr = vpsr.val & IA64_PSR_RI; + if ( !vpsr.ic ) + panic("Interrupt when IC=0\n"); + vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ +} - // non-maskable - if ( vec == NMI_VECTOR ) // NMI - VMX_VPD(vcpu,vhpi) = 32; - else if (vec == ExtINT_VECTOR) //ExtINT - VMX_VPD(vcpu,vhpi) = 16; - else if (vec == -1) - VMX_VPD(vcpu,vhpi) = 0; /* Nothing pending */ +vhpi_detection(VCPU *vcpu) +{ + uint64_t threshold,vhpi; + tpr_t vtpr; + IA64_PSR vpsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + vtpr.val = VPD_CR(vcpu, tpr); - ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, - (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); + threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; + vhpi = VMX_VPD(vcpu,vhpi); + if ( vhpi > threshold ) { + // interrupt actived + generate_exirq (vcpu); + } } +vmx_vexirq(VCPU *vcpu) +{ + static uint64_t vexirq_count=0; + + vexirq_count ++; + printk("Virtual ex-irq %ld\n", vexirq_count); + generate_exirq (vcpu); +} diff --git a/xen/arch/ia64/vmx_entry.S b/xen/arch/ia64/vmx_entry.S index 682a69df8a..261fc591f4 100644 --- a/xen/arch/ia64/vmx_entry.S +++ b/xen/arch/ia64/vmx_entry.S @@ -217,7 +217,7 @@ GLOBAL_ENTRY(ia64_leave_hypervisor) alloc loc0=ar.pfs,0,1,1,0 adds out0=16,r12 ;; - br.call.sptk.many b0=vmx_deliver_pending_interrupt + br.call.sptk.many b0=leave_hypervisor_tail mov ar.pfs=loc0 adds r8=IA64_VPD_BASE_OFFSET,r13 ;; diff --git a/xen/arch/ia64/vmx_hypercall.c b/xen/arch/ia64/vmx_hypercall.c index 5e0d8917eb..fc5f1f8c46 100644 --- a/xen/arch/ia64/vmx_hypercall.c +++ b/xen/arch/ia64/vmx_hypercall.c @@ -141,21 +141,27 @@ void hyper_lock_page(void) static int do_set_shared_page(VCPU *vcpu, u64 gpa) { u64 shared_info, o_info; + struct domain *d = vcpu->domain; + struct vcpu *v; if(vcpu->domain!=dom0) return -EPERM; shared_info = __gpa_to_mpa(vcpu->domain, gpa); o_info = (u64)vcpu->domain->shared_info; - vcpu->domain->shared_info= (shared_info_t *)__va(shared_info); + d->shared_info= (shared_info_t *)__va(shared_info); /* Copy existing shared info into new page */ - if (!o_info) { - memcpy((void*)vcpu->domain->shared_info, (void*)o_info, PAGE_SIZE); - /* If original page belongs to xen heap, then relinguish back - * to xen heap. Or else, leave to domain itself to decide. - */ - if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) - free_xenheap_page(o_info); - } + if (o_info) { + memcpy((void*)d->shared_info, (void*)o_info, PAGE_SIZE); + for_each_vcpu(d, v) { + v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; + } + /* If original page belongs to xen heap, then relinguish back + * to xen heap. Or else, leave to domain itself to decide. + */ + if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) + free_xenheap_page(o_info); + } else + memset(d->shared_info, 0, PAGE_SIZE); return 0; } diff --git a/xen/arch/ia64/vmx_init.c b/xen/arch/ia64/vmx_init.c index f89659ba0c..d313b1b4d9 100644 --- a/xen/arch/ia64/vmx_init.c +++ b/xen/arch/ia64/vmx_init.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -225,6 +226,17 @@ vmx_save_state(struct vcpu *v) vmx_purge_double_mapping(dom_rr7, KERNEL_START, (u64)v->arch.vtlb->ts->vhpt->hash); + /* Need to save KR when domain switch, though HV itself doesn;t + * use them. + */ + v->arch.arch_vmx.vkr[0] = ia64_get_kr(0); + v->arch.arch_vmx.vkr[1] = ia64_get_kr(1); + v->arch.arch_vmx.vkr[2] = ia64_get_kr(2); + v->arch.arch_vmx.vkr[3] = ia64_get_kr(3); + v->arch.arch_vmx.vkr[4] = ia64_get_kr(4); + v->arch.arch_vmx.vkr[5] = ia64_get_kr(5); + v->arch.arch_vmx.vkr[6] = ia64_get_kr(6); + v->arch.arch_vmx.vkr[7] = ia64_get_kr(7); } /* Even guest is in physical mode, we still need such double mapping */ @@ -234,6 +246,7 @@ vmx_load_state(struct vcpu *v) u64 status, psr; u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; u64 pte_xen, pte_vhpt; + int i; status = ia64_pal_vp_restore(v->arch.arch_vmx.vpd, 0); if (status != PAL_STATUS_SUCCESS) @@ -246,6 +259,14 @@ vmx_load_state(struct vcpu *v) (u64)v->arch.vtlb->ts->vhpt->hash, pte_xen, pte_vhpt); + ia64_set_kr(0, v->arch.arch_vmx.vkr[0]); + ia64_set_kr(1, v->arch.arch_vmx.vkr[1]); + ia64_set_kr(2, v->arch.arch_vmx.vkr[2]); + ia64_set_kr(3, v->arch.arch_vmx.vkr[3]); + ia64_set_kr(4, v->arch.arch_vmx.vkr[4]); + ia64_set_kr(5, v->arch.arch_vmx.vkr[5]); + ia64_set_kr(6, v->arch.arch_vmx.vkr[6]); + ia64_set_kr(7, v->arch.arch_vmx.vkr[7]); /* Guest vTLB is not required to be switched explicitly, since * anchored in vcpu */ } @@ -290,7 +311,7 @@ vmx_final_setup_domain(struct domain *d) vmx_create_vp(v); /* Set this ed to be vmx */ - v->arch.arch_vmx.flags = 1; + set_bit(ARCH_VMX_VMCS_LOADED, &v->arch.arch_vmx.flags); /* Other vmx specific initialization work */ } diff --git a/xen/arch/ia64/vmx_ivt.S b/xen/arch/ia64/vmx_ivt.S index 407dc4cd86..90d2398a67 100644 --- a/xen/arch/ia64/vmx_ivt.S +++ b/xen/arch/ia64/vmx_ivt.S @@ -347,11 +347,16 @@ ENTRY(vmx_break_fault) mov r31=pr mov r19=11 mov r30=cr.iim - mov r29=0x1100 + movl r29=0x1100 ;; - cmp4.eq p6,p7=r29,r30 + cmp.eq p6,p7=r30,r0 + (p6) br.sptk vmx_fault_11 + ;; + cmp.eq p6,p7=r29,r30 (p6) br.dptk.few vmx_hypercall_dispatch (p7) br.sptk.many vmx_dispatch_break_fault + ;; + VMX_FAULT(11); END(vmx_break_fault) .org vmx_ia64_ivt+0x3000 @@ -363,6 +368,8 @@ ENTRY(vmx_interrupt) mov r29=cr.ipsr ;; tbit.z p6,p7=r29,IA64_PSR_VM_BIT + tbit.z p0,p15=r29,IA64_PSR_I_BIT + ;; (p7) br.sptk vmx_dispatch_interrupt ;; mov r27=ar.rsc /* M */ @@ -447,7 +454,7 @@ ENTRY(vmx_interrupt) ;; srlz.i ;; - ssm psr.i + (p15) ssm psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST srlz.i // ensure everybody knows psr.ic is back on ;; @@ -508,9 +515,12 @@ END(vmx_interrupt) .org vmx_ia64_ivt+0x3400 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3400 Entry 13 (size 64 bundles) Reserved +ENTRY(vmx_virtual_exirq) VMX_DBG_FAULT(13) - VMX_FAULT(13) - + mov r31=pr + mov r19=13 + br.sptk vmx_dispatch_vexirq +END(vmx_virtual_exirq) .org vmx_ia64_ivt+0x3800 ///////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +886,7 @@ ENTRY(vmx_dispatch_reflection) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -887,8 +897,6 @@ ENTRY(vmx_dispatch_reflection) END(vmx_dispatch_reflection) ENTRY(vmx_dispatch_virtualization_fault) - cmp.eq pEml,pNonEml=r0,r0 /* force pEml =1, save r4 ~ r7 */ - ;; VMX_SAVE_MIN_WITH_COVER_R19 ;; alloc r14=ar.pfs,0,0,3,0 // now it's safe (must be first in insn group!) @@ -899,7 +907,7 @@ ENTRY(vmx_dispatch_virtualization_fault) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -910,6 +918,24 @@ ENTRY(vmx_dispatch_virtualization_fault) END(vmx_dispatch_virtualization_fault) +ENTRY(vmx_dispatch_vexirq) + VMX_SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,1,0 + mov out0=r13 + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_vexirq +END(vmx_dispatch_vexirq) ENTRY(vmx_dispatch_tlb_miss) VMX_SAVE_MIN_WITH_COVER_R19 @@ -922,7 +948,7 @@ ENTRY(vmx_dispatch_tlb_miss) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -947,7 +973,7 @@ ENTRY(vmx_dispatch_break_fault) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15)ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -965,7 +991,7 @@ ENTRY(vmx_hypercall_dispatch) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -987,8 +1013,6 @@ END(vmx_hypercall_dispatch) ENTRY(vmx_dispatch_interrupt) - cmp.ne pEml,pNonEml=r0,r0 /* force pNonEml =1, don't save r4 ~ r7 */ - ;; VMX_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3 ;; alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group @@ -999,7 +1023,7 @@ ENTRY(vmx_dispatch_interrupt) ;; srlz.i ;; - ssm psr.i + (p15) ssm psr.i adds r3=16,r2 // set up second base pointer for SAVE_REST ;; VMX_SAVE_REST diff --git a/xen/arch/ia64/vmx_minstate.h b/xen/arch/ia64/vmx_minstate.h index 76f8e7f065..0356fdbf8d 100644 --- a/xen/arch/ia64/vmx_minstate.h +++ b/xen/arch/ia64/vmx_minstate.h @@ -148,10 +148,14 @@ mov r20=r1; /* A */ \ mov r26=ar.unat; /* M */ \ mov r29=cr.ipsr; /* M */ \ + mov r18=cr.isr; \ COVER; /* B;; (or nothing) */ \ ;; \ - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \ + tbit.z p6,p0=r29,IA64_PSR_VM_BIT; \ + tbit.nz.or p6,p0 = r18,39; \ + ;; \ (p6) br.sptk.few vmx_panic; \ + tbit.z p0,p15=r29,IA64_PSR_I_BIT; \ mov r1=r16; \ /* mov r21=r16; */ \ /* switch from user to kernel RBS: */ \ diff --git a/xen/arch/ia64/vmx_phy_mode.c b/xen/arch/ia64/vmx_phy_mode.c index def87baf9e..16c1a457b5 100644 --- a/xen/arch/ia64/vmx_phy_mode.c +++ b/xen/arch/ia64/vmx_phy_mode.c @@ -119,30 +119,67 @@ physical_mode_init(VCPU *vcpu) vcpu->arch.old_rsc = 0; vcpu->arch.mode_flags = GUEST_IN_PHY; - psr = ia64_clear_ic(); + return; +} - ia64_set_rr((VRN0<domain->arch.emul_phy_rr0.rrval); - ia64_srlz_d(); - ia64_set_rr((VRN4<domain->arch.emul_phy_rr4.rrval); - ia64_srlz_d(); +extern u64 get_mfn(domid_t domid, u64 gpfn, u64 pages); #if 0 - /* FIXME: temp workaround to support guest physical mode */ -ia64_itr(0x1, IA64_TEMP_PHYSICAL, dom0_start, - pte_val(pfn_pte((dom0_start >> PAGE_SHIFT), PAGE_KERNEL)), - 28); -ia64_itr(0x2, IA64_TEMP_PHYSICAL, dom0_start, - pte_val(pfn_pte((dom0_start >> PAGE_SHIFT), PAGE_KERNEL)), - 28); -ia64_srlz_i(); -#endif +void +physical_itlb_miss_domn(VCPU *vcpu, u64 vadr) +{ + u64 psr; + IA64_PSR vpsr; + u64 mppn,gppn,mpp1,gpp1; + struct domain *d; + static u64 test=0; + d=vcpu->domain; + if(test) + panic("domn physical itlb miss happen\n"); + else + test=1; + vpsr.val=vmx_vcpu_get_psr(vcpu); + gppn=(vadr<<1)>>13; + mppn = get_mfn(DOMID_SELF,gppn,1); + mppn=(mppn<<12)|(vpsr.cpl<<7); + gpp1=0; + mpp1 = get_mfn(DOMID_SELF,gpp1,1); + mpp1=(mpp1<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else +// mppn |= PHY_PAGE_WB; + mpp1 |= PHY_PAGE_WB; + psr=ia64_clear_ic(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_stop(); + ia64_srlz_i(); ia64_set_psr(psr); ia64_srlz_i(); return; } +#endif -extern u64 get_mfn(domid_t domid, u64 gpfn, u64 pages); void physical_itlb_miss(VCPU *vcpu, u64 vadr) +{ + physical_itlb_miss_dom0(vcpu, vadr); +} + + +void +physical_itlb_miss_dom0(VCPU *vcpu, u64 vadr) { u64 psr; IA64_PSR vpsr; @@ -150,7 +187,11 @@ physical_itlb_miss(VCPU *vcpu, u64 vadr) vpsr.val=vmx_vcpu_get_psr(vcpu); gppn=(vadr<<1)>>13; mppn = get_mfn(DOMID_SELF,gppn,1); - mppn=(mppn<<12)|(vpsr.cpl<<7)|PHY_PAGE_WB; + mppn=(mppn<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else + mppn |= PHY_PAGE_WB; psr=ia64_clear_ic(); ia64_itc(1,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); @@ -159,12 +200,15 @@ physical_itlb_miss(VCPU *vcpu, u64 vadr) return; } + void physical_dtlb_miss(VCPU *vcpu, u64 vadr) { u64 psr; IA64_PSR vpsr; u64 mppn,gppn; +// if(vcpu->domain!=dom0) +// panic("dom n physical dtlb miss happen\n"); vpsr.val=vmx_vcpu_get_psr(vcpu); gppn=(vadr<<1)>>13; mppn = get_mfn(DOMID_SELF,gppn,1); @@ -209,6 +253,8 @@ vmx_load_all_rr(VCPU *vcpu) * mode in same region */ if (is_physical_mode(vcpu)) { + if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) + panic("Unexpected domain switch in phy emul\n"); ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->domain->arch.emul_phy_rr0.rrval); ia64_set_rr((VRN4 << VRN_SHIFT), @@ -262,15 +308,10 @@ switch_to_virtual_rid(VCPU *vcpu) psr=ia64_clear_ic(); mrr=vmx_vcpu_rr(vcpu,VRN0<arch.mode_flags |= GUEST_PHY_EMUL; switch_to_virtual_rid(vcpu); + } return; } @@ -386,8 +429,10 @@ prepare_if_physical_mode(VCPU *vcpu) void recover_if_physical_mode(VCPU *vcpu) { - if (is_physical_mode(vcpu)) + if (is_physical_mode(vcpu)) { + vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; switch_to_physical_rid(vcpu); + } return; } diff --git a/xen/arch/ia64/vmx_process.c b/xen/arch/ia64/vmx_process.c index 8ab671cdb8..0456d9d001 100644 --- a/xen/arch/ia64/vmx_process.c +++ b/xen/arch/ia64/vmx_process.c @@ -45,7 +45,9 @@ #include #include #include +#include #include +#include /* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ #define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 @@ -53,7 +55,7 @@ extern struct ia64_sal_retval pal_emulator_static(UINT64); extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); extern void rnat_consumption (VCPU *vcpu); - +#define DOMN_PAL_REQUEST 0x110000 IA64FAULT vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { @@ -148,7 +150,10 @@ vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long is regs->r2); #endif vmx_vcpu_increment_iip(current); - } else + }else if(iim == DOMN_PAL_REQUEST){ + pal_emul(current); + vmx_vcpu_increment_iip(current); + } else vmx_reflect_interruption(ifa,isr,iim,11); } @@ -187,26 +192,43 @@ void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, // ONLY gets called from ia64_leave_kernel // ONLY call with interrupts disabled?? (else might miss one?) // NEVER successful if already reflecting a trap/fault because psr.i==0 -void vmx_deliver_pending_interrupt(struct pt_regs *regs) +void leave_hypervisor_tail(struct pt_regs *regs) { struct domain *d = current->domain; struct vcpu *v = current; // FIXME: Will this work properly if doing an RFI??? if (!is_idle_task(d) ) { // always comes from guest - //vcpu_poke_timer(v); - //if (vcpu_deliverable_interrupts(v)) { - // unsigned long isr = regs->cr_ipsr & IA64_PSR_RI; - // foodpi(); - // reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR); - //} extern void vmx_dorfirfi(void); struct pt_regs *user_regs = vcpu_regs(current); + if (local_softirq_pending()) + do_softirq(); + local_irq_disable(); + if (user_regs != regs) printk("WARNING: checking pending interrupt in nested interrupt!!!\n"); - if (regs->cr_iip == *(unsigned long *)vmx_dorfirfi) - return; - vmx_check_pending_irq(v); + + /* VMX Domain N has other interrupt source, saying DM */ + if (test_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags)) + vmx_intr_assist(v); + + /* FIXME: Check event pending indicator, and set + * pending bit if necessary to inject back to guest. + * Should be careful about window between this check + * and above assist, since IOPACKET_PORT shouldn't be + * injected into vmx domain. + * + * Now hardcode the vector as 0x10 temporarily + */ + if (event_pending(v)&&(!((v->arch.arch_vmx.in_service[0])&(1UL<<0x10)))) { + VPD_CR(v, irr[0]) |= 1UL << 0x10; + v->arch.irq_new_pending = 1; + } + + if ( v->arch.irq_new_pending ) { + v->arch.irq_new_pending = 0; + vmx_check_pending_irq(v); + } } } @@ -244,7 +266,11 @@ void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) return; } if((vec==2)&&(!vpsr.dt)){ - physical_dtlb_miss(vcpu, vadr); + if(vcpu->domain!=dom0&&__gpfn_is_io(vcpu->domain,(vadr<<1)>>(PAGE_SHIFT+1))){ + emulate_io_inst(vcpu,((vadr<<1)>>1),4); // UC + }else{ + physical_dtlb_miss(vcpu, vadr); + } return; } vrr = vmx_vcpu_rr(vcpu,vadr); @@ -255,6 +281,11 @@ void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) // prepare_if_physical_mode(vcpu); if(data=vtlb_lookup_ex(vtlb, vrr.rid, vadr,type)){ + if(vcpu->domain!=dom0&&type==DSIDE_TLB && __gpfn_is_io(vcpu->domain, data->ppn>>(PAGE_SHIFT-12))){ + vadr=(vadr&((1UL<ps)-1))+(data->ppn>>(data->ps-12)<ps); + emulate_io_inst(vcpu, vadr, data->ma); + return IA64_FAULT; + } if ( data->ps != vrr.ps ) { machine_tlb_insert(vcpu, data); } diff --git a/xen/arch/ia64/vmx_support.c b/xen/arch/ia64/vmx_support.c new file mode 100644 index 0000000000..ed92bad2b0 --- /dev/null +++ b/xen/arch/ia64/vmx_support.c @@ -0,0 +1,159 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_support.c: vmx specific support interface. + * Copyright (c) 2005, Intel Corporation. + * Kun Tian (Kevin Tian) (Kevin.tian@intel.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include +#include +#include +#include +#include + +/* + * I/O emulation should be atomic from domain point of view. However, + * when emulation code is waiting for I/O completion by do_block, + * other events like DM interrupt, VBD, etc. may come and unblock + * current exection flow. So we have to prepare for re-block if unblocked + * by non I/O completion event. + */ +void vmx_wait_io(void) +{ + struct vcpu *v = current; + struct domain *d = v->domain; + extern void do_block(); + + do { + if (!test_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) + do_block(); + + /* Unblocked when some event is coming. Clear pending indication + * immediately if deciding to go for io assist + */ + if (test_and_clear_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) { + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + vmx_io_assist(v); + } + + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + /* + * Latest event is not I/O completion, so clear corresponding + * selector and pending indication, to allow real event coming + */ + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + + /* Here atually one window is leaved before selector is cleared. + * However this window only delay the indication to coming event, + * nothing losed. Next loop will check I/O channel to fix this + * window. + */ + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + } + else + break; + } while (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)); +} + +/* + * Only place to call vmx_io_assist is mmio/legacy_io emulation. + * Since I/O emulation is synchronous, it shouldn't be called in + * other places. This is not like x86, since IA-64 implements a + * per-vp stack without continuation. + */ +void vmx_io_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + ioreq_t *p; + + /* + * This shared page contains I/O request between emulation code + * and device model. + */ + vio = (vcpu_iodata_t *)v->arch.arch_vmx.vmx_platform.shared_page_va; + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + + p = &vio->vp_ioreq; + + if (p->state == STATE_IORESP_HOOK) + panic("Not supported: No hook available for DM request\n"); + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + if (p->state != STATE_IORESP_READY) { + /* Can't do_block here, for the same reason as other places to + * use vmx_wait_io. Simple return is safe since vmx_wait_io will + * try to block again + */ + return; + } else + p->state = STATE_INVALID; + + clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + } else + return; /* Spurous event? */ +} + +/* + * VMX domainN has two types of interrupt source: lsapic model within + * HV, and device model within domain 0 (service OS). There're another + * pending array in share page, manipulated by device model directly. + * To conform to VT-i spec, we have to sync pending bits in shared page + * into VPD. This has to be done before checking pending interrupt at + * resume to guest. For domain 0, all the interrupt sources come from + * HV, which then doesn't require this assist. + */ +void vmx_intr_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + struct domain *d = v->domain; + extern void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, + unsigned long *pend_irr); + + /* I/O emulation is atomic, so it's impossible to see execution flow + * out of vmx_wait_io, when guest is still waiting for response. + */ + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) + panic("!!!Bad resume to guest before I/O emulation is done.\n"); + + /* Clear indicator specific to interrupt delivered from DM */ + if (test_and_clear_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) { + if (!d->shared_info->evtchn_pending[IOPACKET_PORT >> 5]) + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + + if (!v->vcpu_info->evtchn_pending_sel) + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + } + + /* Even without event pending, we still need to sync pending bits + * between DM and vlsapic. The reason is that interrupt delivery + * shares same event channel as I/O emulation, with corresponding + * indicator possibly cleared when vmx_wait_io(). + */ + vio = (vcpu_iodata_t *)v->arch.arch_vmx.vmx_platform.shared_page_va; + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + + vmx_vcpu_pend_batch_interrupt(v, &vio->vp_intr[0]); + memset(&vio->vp_intr[0], 0, sizeof(vio->vp_intr)); + return; +} diff --git a/xen/arch/ia64/vmx_vcpu.c b/xen/arch/ia64/vmx_vcpu.c index 05c211d428..1e4046389c 100644 --- a/xen/arch/ia64/vmx_vcpu.c +++ b/xen/arch/ia64/vmx_vcpu.c @@ -23,8 +23,6 @@ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) */ - - #include #include #include @@ -71,8 +69,8 @@ //unsigned long last_guest_rsm = 0x0; struct guest_psr_bundle{ - unsigned long ip; - unsigned long psr; + unsigned long ip; + unsigned long psr; }; struct guest_psr_bundle guest_psr_buf[100]; @@ -107,20 +105,24 @@ vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value) IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA )); + if ( !old_psr.i && (value & IA64_PSR_I) ) { + // vpsr.i 0->1 + vcpu->arch.irq_new_condition = 1; + } new_psr.val=vmx_vcpu_get_psr(vcpu); { - struct xen_regs *regs = vcpu_regs(vcpu); - guest_psr_buf[guest_psr_index].ip = regs->cr_iip; - guest_psr_buf[guest_psr_index].psr = new_psr.val; - if (++guest_psr_index >= 100) - guest_psr_index = 0; + struct xen_regs *regs = vcpu_regs(vcpu); + guest_psr_buf[guest_psr_index].ip = regs->cr_iip; + guest_psr_buf[guest_psr_index].psr = new_psr.val; + if (++guest_psr_index >= 100) + guest_psr_index = 0; } #if 0 if (old_psr.i != new_psr.i) { - if (old_psr.i) - last_guest_rsm = vcpu_regs(vcpu)->cr_iip; - else - last_guest_rsm = 0; + if (old_psr.i) + last_guest_rsm = vcpu_regs(vcpu)->cr_iip; + else + last_guest_rsm = 0; } #endif @@ -270,8 +272,8 @@ check_entry(u64 va, u64 ps, char *str) { va &= ~ (PSIZE(ps)-1); if ( va == 0x2000000002908000UL || - va == 0x600000000000C000UL ) { - stop(); + va == 0x600000000000C000UL ) { + stop(); } if (tlb_debug) printf("%s at %lx %lx\n", str, va, 1UL<arch.irq_new_condition = 1; + return IA64_NO_FAULT; +} diff --git a/xen/arch/ia64/vmx_virt.c b/xen/arch/ia64/vmx_virt.c index 29b1164196..7e8f658bac 100644 --- a/xen/arch/ia64/vmx_virt.c +++ b/xen/arch/ia64/vmx_virt.c @@ -1276,7 +1276,13 @@ IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst) } - +static void post_emulation_action(VCPU *vcpu) +{ + if ( vcpu->arch.irq_new_condition ) { + vcpu->arch.irq_new_condition = 0; + vhpi_detection(vcpu); + } +} //#define BYPASS_VMAL_OPCODE extern IA64_SLOT_TYPE slot_types[0x20][3]; @@ -1336,7 +1342,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; if (!slot) inst.inst = bundle.slot0; else if (slot == 1) - inst.inst = bundle.slot1a + (bundle.slot1b<<23); + inst.inst = bundle.slot1a + (bundle.slot1b<<18); else if (slot == 2) inst.inst = bundle.slot2; else printf("priv_handle_op: illegal slot: %d\n", slot); slot_type = slot_types[bundle.template][slot]; @@ -1478,9 +1484,11 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { status=IA64_FAULT; break; default: - printf("unknown cause %d:\n", cause); + printf("unknown cause %d, iip: %lx, ipsr: %lx\n", cause,regs->cr_iip,regs->cr_ipsr); + while(1); /* For unknown cause, let hardware to re-execute */ status=IA64_RETRY; + break; // panic("unknown cause in virtualization intercept"); }; @@ -1494,6 +1502,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { } recover_if_physical_mode(vcpu); + post_emulation_action (vcpu); //TODO set_irq_check(v); return; diff --git a/xen/arch/ia64/vtlb.c b/xen/arch/ia64/vtlb.c index 86565531bf..89453b93bb 100644 --- a/xen/arch/ia64/vtlb.c +++ b/xen/arch/ia64/vtlb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #define MAX_CCH_LENGTH 40 @@ -401,6 +401,8 @@ static void vhpt_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) panic("Can't convert to machine VHPT entry\n"); } hash_table->next = cch; + if(hash_table->tag==hash_table->next->tag) + while(1); } return /*hash_table*/; } @@ -466,10 +468,11 @@ int cch_depth=0; static thash_data_t *thash_rem_cch(thash_cb_t *hcb, thash_data_t *cch) { thash_data_t *next; - + if ( ++cch_depth > MAX_CCH_LENGTH ) { printf ("cch length > MAX_CCH_LENGTH, exceed the expected length\n"); - } + while(1); + } if ( cch -> next ) { next = thash_rem_cch(hcb, cch->next); } diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index d95eebfc9f..b4cc8f52c9 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -30,7 +30,6 @@ struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu }; #ifdef CLONE_DOMAIN0 struct domain *clones[CLONE_DOMAIN0]; #endif -extern struct domain *dom0; extern unsigned long domain0_ready; int find_max_pfn (unsigned long, unsigned long, void *); diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index e64246d418..71bf6ea2e3 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -49,6 +49,7 @@ typedef unsigned long physaddr_t; extern unsigned long xenheap_phys_end; extern unsigned long xen_pstart; extern unsigned long xenheap_size; +extern struct domain *dom0; extern unsigned long dom0_start; extern unsigned long dom0_size; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 717a7fcf23..0b270a7372 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -42,8 +42,6 @@ struct arch_domain { * max_pages in domain struct, which indicates maximum memory size */ unsigned long max_pfn; - unsigned int section_nr; - mm_section_t *sections; /* Describe memory hole except for Dom0 */ #endif //CONFIG_VTI u64 xen_vastart; u64 xen_vaend; @@ -88,6 +86,8 @@ struct arch_vcpu { void (*schedule_tail) (struct vcpu *); struct trap_bounce trap_bounce; thash_cb_t *vtlb; + char irq_new_pending; + char irq_new_condition; // vpsr.i/vtpr change, check for pending VHPI //for phycial emulation unsigned long old_rsc; int mode_flags; diff --git a/xen/include/asm-ia64/privop.h b/xen/include/asm-ia64/privop.h index 4cad79ee3a..a8cf870d4b 100644 --- a/xen/include/asm-ia64/privop.h +++ b/xen/include/asm-ia64/privop.h @@ -138,6 +138,19 @@ typedef union U_INST64_M47 { IA64_INST inst; struct { unsigned long qp:6, un14:14, r3:7, x6:6, x3:3, un1:1, major:4; }; } INST64_M47; +typedef union U_INST64_M1{ + IA64_INST inst; + struct { unsigned long qp:6, r1:7, un7:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M1; +typedef union U_INST64_M4 { + IA64_INST inst; + struct { unsigned long qp:6, un7:7, r2:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M4; +typedef union U_INST64_M6 { + IA64_INST inst; + struct { unsigned long qp:6, f1:7, un7:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M6; + #endif // CONFIG_VTI typedef union U_INST64 { @@ -151,6 +164,11 @@ typedef union U_INST64 { INST64_I26 I26; // mov register to ar (I unit) INST64_I27 I27; // mov immediate to ar (I unit) INST64_I28 I28; // mov from ar (I unit) +#ifdef CONFIG_VTI + INST64_M1 M1; // ld integer + INST64_M4 M4; // st integer + INST64_M6 M6; // ldfd floating pointer +#endif // CONFIG_VTI INST64_M28 M28; // purge translation cache entry INST64_M29 M29; // mov register to ar (M unit) INST64_M30 M30; // mov immediate to ar (M unit) diff --git a/xen/include/asm-ia64/vmx.h b/xen/include/asm-ia64/vmx.h index 3610bd5cd6..2f5fadd99a 100644 --- a/xen/include/asm-ia64/vmx.h +++ b/xen/include/asm-ia64/vmx.h @@ -35,4 +35,6 @@ extern vmx_insert_double_mapping(u64,u64,u64,u64,u64); extern void vmx_purge_double_mapping(u64, u64, u64); extern void vmx_change_double_mapping(struct vcpu *v, u64 oldrr7, u64 newrr7); +extern void vmx_wait_io(void); +extern void vmx_io_assist(struct vcpu *v); #endif /* _ASM_IA64_VT_H */ diff --git a/xen/include/asm-ia64/vmx_phy_mode.h b/xen/include/asm-ia64/vmx_phy_mode.h index 20c669e69c..039d302ea2 100644 --- a/xen/include/asm-ia64/vmx_phy_mode.h +++ b/xen/include/asm-ia64/vmx_phy_mode.h @@ -83,6 +83,7 @@ #define IA64_RSC_MODE 0x0000000000000003 #define XEN_RR7_RID (0xf00010) #define GUEST_IN_PHY 0x1 +#define GUEST_PHY_EMUL 0x2 extern int valid_mm_mode[]; extern int mm_switch_table[][8]; extern void physical_mode_init(VCPU *); diff --git a/xen/include/asm-ia64/vmx_vcpu.h b/xen/include/asm-ia64/vmx_vcpu.h index dc4e0977b7..a47ceab280 100644 --- a/xen/include/asm-ia64/vmx_vcpu.h +++ b/xen/include/asm-ia64/vmx_vcpu.h @@ -53,7 +53,7 @@ #define VMM_RR_SHIFT 20 #define VMM_RR_MASK ((1UL<domain->domain_id) << VMM_RR_SHIFT) extern u64 indirect_reg_igfld_MASK ( int type, int index, u64 value); extern u64 cr_igfld_mask (int index, u64 value); @@ -69,7 +69,7 @@ extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, UINT64 value); extern IA64FAULT vmx_vcpu_cover(VCPU *vcpu); extern thash_cb_t *vmx_vcpu_get_vtlb(VCPU *vcpu); extern thash_cb_t *vmx_vcpu_get_vhpt(VCPU *vcpu); -ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); +extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); extern IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val); extern IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval); extern IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval); @@ -112,10 +112,10 @@ extern uint64_t guest_read_vivr(VCPU *vcpu); extern void vmx_inject_vhpi(VCPU *vcpu, u8 vec); extern void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector); extern struct virutal_platform_def *vmx_vcpu_get_plat(VCPU *vcpu); -extern void memread_p(VCPU *vcpu, void *src, void *dest, size_t s); -extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s); -extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s); -extern void memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s); +extern void memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); +extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); +extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); +extern void memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); /************************************************************************** @@ -401,14 +401,8 @@ vmx_vcpu_set_lid(VCPU *vcpu, u64 val) VPD_CR(vcpu,lid)=val; return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_tpr(VCPU *vcpu, u64 val) -{ - VPD_CR(vcpu,tpr)=val; - //TODO - return IA64_NO_FAULT; -} +extern IA64FAULT vmx_vcpu_set_tpr(VCPU *vcpu, u64 val); + static inline IA64FAULT vmx_vcpu_set_eoi(VCPU *vcpu, u64 val) diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h index be29ed1d47..1a18f03661 100644 --- a/xen/include/asm-ia64/vmx_vpd.h +++ b/xen/include/asm-ia64/vmx_vpd.h @@ -19,8 +19,8 @@ * Kun Tian (Kevin Tian) (kevin.tian@intel.com) */ -#ifndef _VPD_H_ -#define _VPD_H_ +#ifndef _ASM_IA64_VMX_VPD_H_ +#define _ASM_IA64_VMX_VPD_H_ #ifndef __ASSEMBLY__ @@ -123,6 +123,7 @@ struct arch_vmx_struct { vpd_t *vpd; vtime_t vtm; unsigned long vrr[8]; + unsigned long vkr[8]; unsigned long mrr5; unsigned long mrr6; unsigned long mrr7; @@ -145,6 +146,7 @@ struct arch_vmx_struct { #define ARCH_VMX_VMCS_LAUNCH 1 /* Needs VMCS launch */ #define ARCH_VMX_VMCS_RESUME 2 /* Needs VMCS resume */ #define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */ +#define ARCH_VMX_INTR_ASSIST 4 /* Need DM's assist to issue intr */ #define VMX_DEBUG 1 @@ -191,4 +193,4 @@ extern unsigned int opt_vmx_debug_level; #define VPD_VMM_VAIL_START_OFFSET 31744 -#endif /* _VPD_H_ */ +#endif /* _ASM_IA64_VMX_VPD_H_ */ diff --git a/xen/include/asm-ia64/xenprocessor.h b/xen/include/asm-ia64/xenprocessor.h index abc13dacee..da9a1d6c7b 100644 --- a/xen/include/asm-ia64/xenprocessor.h +++ b/xen/include/asm-ia64/xenprocessor.h @@ -166,6 +166,16 @@ typedef union{ }; } ipi_d_t; +typedef union { + __u64 val; + struct { + __u64 ig0 : 4; + __u64 mic : 4; + __u64 rsv : 8; + __u64 mmi : 1; + __u64 ig1 : 47; + }; +} tpr_t; #define IA64_ISR_CODE_MASK0 0xf #define IA64_UNIMPL_DADDR_FAULT 0x30 diff --git a/xen/include/asm-ia64/xensystem.h b/xen/include/asm-ia64/xensystem.h index 6fadb60ebe..0de4365b47 100644 --- a/xen/include/asm-ia64/xensystem.h +++ b/xen/include/asm-ia64/xensystem.h @@ -33,6 +33,8 @@ #ifdef CONFIG_VTI extern struct task_struct *vmx_ia64_switch_to (void *next_task); #define __switch_to(prev,next,last) do { \ + ia64_save_fpu(prev->arch._thread.fph); \ + ia64_load_fpu(next->arch._thread.fph); \ if (VMX_DOMAIN(prev)) \ vmx_save_state(prev); \ else { \ diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index e9b6767c76..34e9f1c0ae 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -181,6 +181,16 @@ typedef struct { } arch_shared_info_t; // DON'T PACK typedef struct vcpu_guest_context { +#define VGCF_FPU_VALID (1<<0) +#define VGCF_VMX_GUEST (1<<1) +#define VGCF_IN_KERNEL (1<<2) + unsigned long flags; /* VGCF_* flags */ + unsigned long pt_base; /* PMT table base */ + unsigned long pt_max_pfn; /* Max pfn including holes */ + unsigned long share_io_pg; /* Shared page for I/O emulation */ + unsigned long vm_assist; /* VMASST_TYPE_* bitmap, now none on IPF */ + unsigned long guest_iip; /* Guest entry point */ + struct pt_regs regs; arch_vcpu_info_t vcpu; arch_shared_info_t shared; -- 2.30.2